package top.dingwen.io.treasure.websocket.autoconfigure;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
import top.dingwen.io.treasure.websocket.constant.WebSocketConstant;
import top.dingwen.io.treasure.websocket.core.HeartbeatCheckJob;
import top.dingwen.io.treasure.websocket.core.call.DefaultReceiveMsgCall;
import top.dingwen.io.treasure.websocket.core.call.DefaultSendMsgCall;
import top.dingwen.io.treasure.websocket.core.call.IReceiveMsgCall;
import top.dingwen.io.treasure.websocket.core.call.ISendMsgCall;
import top.dingwen.io.treasure.websocket.core.interceptor.WebSocketInterceptor;
import top.dingwen.io.treasure.websocket.core.listener.WebSocketTopicListener;
import top.dingwen.io.treasure.websocket.web.WebSocketIndexController;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * WebsocketAutoconfiguration : Websocket自动配置类
 *
 * @author dingwen
 * @since 2024/10/16 13:28
 */
@ConditionalOnProperty(value = "dingwen.treasure.websocket.enabled", havingValue = "true")
@Configuration
@EnableConfigurationProperties(WebSocketProperties.class)
@Lazy(value = false)
@Slf4j
@EnableWebSocket
public class WebSocketAutoconfiguration {

    @Resource
    private WebSocketProperties webSocketProperties;

    /**
     * 初始化
     */
    @PostConstruct
    public void init() {
        if (log.isInfoEnabled()) {
            log.info("{} \n\n" +
                    "                _                    _        _   \n" +
                    "              | |                  | |      | |  \n" +
                    " __      _____| |__  ___  ___   ___| | _____| |_ \n" +
                    " \\ \\ /\\ / / _ \\ '_ \\/ __|/ _ \\ / __| |/ / _ \\ __|\n" +
                    "  \\ V  V /  __/ |_) \\__ \\ (_) | (__|   <  __/ |_ \n" +
                    "   \\_/\\_/ \\___|_.__/|___/\\___/ \\___|_|\\_\\___|\\__|\n" +
                    "                                                 \n" +
                    "                       \n" +
                    "                       ", WebSocketConstant.WS_L_O_S);
            log.info("{},读取到的配置如下:\n{}", WebSocketConstant.WS_L_O_S, JSONUtil.toJsonPrettyStr(webSocketProperties));
            log.info("{}，启动成功", WebSocketConstant.WS_L_O_S);
        }
    }

    /**
     * socket服务配置
     *
     * @return {@link WebSocketConfigurer }
     */
    @Bean
    @ConditionalOnMissingBean(name = "webSocketConfigurer")
    public WebSocketConfigurer webSocketConfigurer() {
        log.info("{},{},已成功加载", WebSocketConstant.WS_L_O_S, WebSocketConstant.WS_L_C);
        // 返回一个WebSocketConfigurer对象，用于配置WebSocket
        return registry -> registry
                // 添加WebSocket处理程序和拦截器到指定路径，设置允许的跨域来源
                .addHandler(webSocketHandle(), webSocketProperties.getPath())
                .addInterceptors(webSocketInterceptor())
                .setAllowedOrigins(webSocketProperties.getAllowedOrigins());
    }

    /**
     * 创建ServletServerContainerFactoryBean对象，用于配置WebSocket服务器
     * @return {@link ServletServerContainerFactoryBean }
     */
    @Bean
    @ConditionalOnMissingBean(name = "servletServerContainerFactoryBean")
    public ServletServerContainerFactoryBean servletServerContainerFactoryBean() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        // 文本消息缓冲区大小
        container.setMaxTextMessageBufferSize(webSocketProperties.getMaxTextMessageBufferSize());
        // 二进制消息缓冲区大小
        container.setMaxBinaryMessageBufferSize(webSocketProperties.getMaxBinaryMessageBufferSize());
        return container;
    }
    /**
     * 心跳拦截器
     *
     * @return {@link HandshakeInterceptor }
     */
    @Bean
    @ConditionalOnMissingBean(HandshakeInterceptor.class)
    public HandshakeInterceptor webSocketInterceptor() {
        log.info("{},{},已成功加载", WebSocketConstant.WS_L_O_S, WebSocketConstant.WS_L_I);
        return new WebSocketInterceptor();
    }

    /**
     * 连接处理器
     *
     * @return {@link WebSocketHandler }
     */
    @Bean
    @ConditionalOnMissingBean(name = "webSocketHandle")
    public WebSocketHandler webSocketHandle() {
        log.info("{},{},已成功加载", WebSocketConstant.WS_L_O_S, WebSocketConstant.WS_L_H);
        return new top.dingwen.io.treasure.websocket.core.handler.WebSocketHandler();
    }

    /**
     * 主题监听器
     *
     * @return {@link WebSocketTopicListener }
     */
    @Bean
    @ConditionalOnMissingBean(WebSocketTopicListener.class)
    public WebSocketTopicListener topicListener() {
        log.info("{},{},已成功加载", WebSocketConstant.WS_L_O_S, WebSocketConstant.WS_L_TL);
        return new WebSocketTopicListener();
    }

    /**
     * 默认API
     *
     * @return {@link WebSocketIndexController }
     */
    @Bean
    @ConditionalOnProperty(name = "dingwen.treasure.websocket.defaultApiEnabled", havingValue = "true")
    @ConditionalOnMissingBean(WebSocketIndexController.class)
    public WebSocketIndexController webSocketIndexController() {
        log.info("{},{},已成功加载", WebSocketConstant.WS_L_O_S, WebSocketConstant.WS_L_API);
        return new WebSocketIndexController();
    }

    /**
     * 心跳检查任务
     * @return {@link HeartbeatCheckJob }
     */
    @Bean
    @ConditionalOnProperty(name = "dingwen.treasure.websocket.heartbeatEnabled", havingValue = "true")
    @ConditionalOnMissingBean(HeartbeatCheckJob.class)
    public HeartbeatCheckJob heartbeatCheckJob() {
        log.info("{},{},已成功加载", WebSocketConstant.WS_L_O_S, WebSocketConstant.WS_L_HB_CJ);
        return new HeartbeatCheckJob();
    }

    /**
     * 默认接收消息处理回调
     * @return {@link IReceiveMsgCall }
     */
    @Bean
    @ConditionalOnMissingBean(IReceiveMsgCall.class)
    public IReceiveMsgCall receiveMsgCall() {
        log.info("{},{},已成功加载", WebSocketConstant.WS_L_O_S, WebSocketConstant.WS_L_D_RMC);
        return new DefaultReceiveMsgCall();
    }

    /**
     * 默认发送消息处理回调
     * @return {@link ISendMsgCall }
     */
    @Bean
    @ConditionalOnMissingBean(ISendMsgCall.class)
    public ISendMsgCall sendMsgCall() {
        log.info("{},{},已成功加载", WebSocketConstant.WS_L_O_S, WebSocketConstant.WS_L_D_SMC);
        return new DefaultSendMsgCall();
    }
}
